/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : flash demo code 
* HISTORY     : Initial version.
* @file     flash_demo.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#include "flash_demo.h"
#include "console.h"
#include "led_hw.h"
#include "Mcu_lld.h"
#include "common.h"

#if 1U
#define cDEBUG          PSPRINTF
#else
#define cDEBUG(...)
#endif

/*******************************************************************************
 * @brief      Bug
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Bug(void)
{
    cDEBUG("\n Flash test fail! \n");
#if 0U
    while (1)
    {
        LED_Set(LED3, LED_OFF);
        delay_ms(500U);
        LED_Set(LED3, LED_ON);
        delay_ms(500U);
    }
#endif
}

static uint32_t const CFlash_LSL_All[6] = {CFLASH_LMS_LSL0, CFLASH_LMS_LSL1,
                                          CFLASH_LMS_LSL2, CFLASH_LMS_LSL3,
                                          CFLASH_LMS_LSL4, CFLASH_LMS_LSL5};
static uint32_t const CFlash_MSL_All[2] = {CFLASH_LMS_MSL0, CFLASH_LMS_MSL1};
static uint32_t const DFlash_LSL_All[4] = {DFLASH_LMS_LSL0, DFLASH_LMS_LSL1,
                                           DFLASH_LMS_LSL2, DFLASH_LMS_LSL3};

/*******************************************************************************
 * @brief      FLASH_Test_Case1
 *             Read Flash register(after reset) and comparison.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case1(void) /* PRQA S 3219 */
{
    uint32_t retStatus;
    uint32_t regVal;
    uint32_t regValSpec;

    retStatus = 0U;

    cDEBUG("\n FLASH_Test_Case1 Start!\n");

    regVal = (uint32_t)(CFLASH.MCR.R);
    regValSpec = CFLASH_MCR_SIZE2|CFLASH_MCR_LAS2|CFLASH_MCR_DONE|CFLASH_MCR_PEG;
    if (regVal != regValSpec)/* regValSpec = 0x04200600u */
    {
//        cDEBUG("\n CFLASH MCR wrong: 0x%x!\n", regVal);
//    	cDEBUG("This register readout value is not consistent with the actual value.\r\n Please refer to the manual.\n");
        retStatus = 0x01U;
    }
    else
    {
        cDEBUG("\n CFLASH MCR success!\n");
    }

    regVal = (uint32_t)(CFLASH.LML.R);
    regValSpec = (CFlash_WordRead(CFLASH_NVLML_H) & (CFLASH_LML_LOCK | CFLASH_LML_TSLK));
    if (regVal != regValSpec)/* regValSpec = 0x0013003Fu */
    {
        cDEBUG("\n CFLASH LML wrong: 0x%x!\n", regVal);
        retStatus |= 0x02u;
    }else{
    	cDEBUG("\n CFLASH LML success!\n");
    }

    regVal = (uint32_t)(CFLASH.HBL.R);
    regValSpec = (CFlash_WordRead(CFLASH_NVHBL_H) & (CFLASH_HBL_LOCK));
    if (regVal != regValSpec)/* regValSpec = 0x0000FFFFu */
    {
        cDEBUG("\n CFLASH HBL wrong: 0x%x!\n", regVal);
        retStatus |= 0x04u;
    }else{
    	cDEBUG("\n CFLASH HBL success!\n");
    }

    regVal = (uint32_t)(CFLASH.SLL.R);
    regValSpec = (CFlash_WordRead(CFLASH_NVSLL_H) & (CFLASH_SLL_LOCK | CFLASH_SLL_STSLK));
    if (regVal != regValSpec)/* regValSpec = 0x0013003Fu */
    {
        cDEBUG("\n CFLASH SLL wrong: 0x%x!\n", regVal);
        retStatus |= 0x08u;
    }else{
    	cDEBUG("\n CFLASH SLL success!\n");
    }

    regVal = (uint32_t)(CFLASH.LMS.R);
    regValSpec = CFLASH_LMS_NULL;
    if (regVal != regValSpec)
    {
        cDEBUG("\n CFLASH LMS wrong: 0x%x!\n", regVal);
        retStatus |= 0x10U;
    }
    else
    {
        cDEBUG("\n CFLASH LMS success!\n");
    }

    regVal = (uint32_t)(CFLASH.HBS.R);
    regValSpec = CFLASH_HBS_NULL;
    if (regVal != regValSpec)
    {
        cDEBUG("\n CFLASH HBS wrong: 0x%x!\n", regVal);
        retStatus |= 0x20U;
    }
    else
    {
        cDEBUG("\n CFLASH HBS success!\n");
    }

    regVal = (uint32_t)(CFLASH.ADR.R);
    regValSpec = 0x00000000U;
    if (regVal != regValSpec)
    {
        cDEBUG("\n CFLASH ADR wrong: 0x%x!\n", regVal);
        retStatus |= 0x40U;
    }
    else
    {
        cDEBUG("\n CFLASH ADR success!\n");
    }

    /* The CCFC2011BC PFCR0 feature design only has 
     * RWSC/RWWC/P0_BFE, and no other bits */
    regVal = (uint32_t)(CFLASH.PFCR0.R);
    regValSpec = PFCR0_FIXED_VALUE|PFCR_BK_RWSC_4|PFCR_BK_RWWC_7|PFCR_B_P0_BFE;
    if (regVal != regValSpec)/* regValSpec = 0x18C980EDu */
    {
        cDEBUG("\n CFLASH PFCR0 wrong: 0x%x!\n", regVal);
        retStatus |= 0x80U;
    }
    else
    {
        cDEBUG("\n CFLASH PFCR0 success!\n");
    }

    /* The CCFC2011BC PFCR1 feature design only has 
     * RWSC/RWWC/P0_BFE, and no other bits */
    regVal = (uint32_t)(CFLASH.PFCR1.R);
    regValSpec = PFCR1_FIXED_VALUE|PFCR_BK_RWSC_4|PFCR_BK_RWWC_7|PFCR_B_P0_BFE;
    if (regVal != regValSpec)/* regValSpec = 0x18C98081u */
    {
        cDEBUG("\n CFLASH PFCR1 wrong: 0x%x!\n", regVal);
        retStatus |= 0x100U;
    }
    else
    {
        cDEBUG("\n CFLASH PFCR1 success!\n");
    }

    /* The CCFC2011BC PFAPR feature design only has 
     * PFAPR_M0AP_RW and no other bits */
    regVal = (uint32_t)(CFLASH.PFAPR.R);
    regValSpec =  PFAPR_M0AP_RW;
    if (regVal != regValSpec)/* regValSpec = 0x00000003u */
    {
        cDEBUG("\n CFLASH PFAPR wrong: 0x%x!\n", regVal);
        retStatus |= 0x200U;
    }
    else
    {
        cDEBUG("\n CFLASH PFAPR success!\n");
    }

    regVal = (uint32_t)(DFLASH.MCR.R);
    regValSpec = DFLASH_MCR_SIZE6|DFLASH_MCR_LAS6|DFLASH_MCR_DONE|DFLASH_MCR_PEG;
    if (regVal != regValSpec)/* regValSpec = 0x06600600u */
    {
        cDEBUG("\n DFLASH MCR wrong: 0x%x!\n", regVal);
        retStatus |= 0x0400U;
    }
    else
    {
        cDEBUG("\n DFLASH MCR success!\n");
    }

    regVal = (uint32_t)(DFLASH.LML.R);
    regValSpec = (DFLASH_LML_LOCK | DFLASH_LML_TSLK);
    if (regVal != regValSpec)/* regValSpec = 0x0010000Fu */
    {
        cDEBUG("\n DFLASH LML wrong: 0x%x!\n", regVal);
        retStatus |= 0x0800u;
    }else{
    	cDEBUG("\n DFLASH LML success!\n");
    }

    regVal = (uint32_t)(DFLASH.SLL.R);
    regValSpec = (DFLASH_SLL_LOCK | DFLASH_SLL_STSLK);
    if (regVal != regValSpec)/* regValSpec = 0x0010000Fu */
    {
        cDEBUG("\n DFLASH SLL wrong: 0x%x!\n", regVal);
        retStatus |= 0x1000u;
    }else{
    	cDEBUG("\n DFLASH SLL success!\n");
    }

    regVal = (uint32_t)(DFLASH.LMS.R);
    regValSpec = DFLASH_LMS_NULL;
    if (regVal != regValSpec)/* regValSpec = 0x00000000u */
    {
        cDEBUG("\n DFLASH LMS wrong: 0x%x!\n", regVal);
        retStatus |= 0x2000U;
    }
    else
    {
        cDEBUG("\n DFLASH LMS success!\n");
    }

    regVal = (uint32_t)(DFLASH.ADR.R);
    regValSpec = 0x00000000U;
    if (regVal != regValSpec)/* regValSpec = 0x00000000u */
    {
        cDEBUG("\n DFLASH ADR wrong: 0x%x!\n", regVal);
        retStatus |= 0x4000U;
    }
    else
    {
        cDEBUG("\n DFLASH ADR success!\n");
    }

    if (retStatus != 0U)
    {
//        Bug();
//    	cDEBUG("This module readout value is not consistent with the actual value.\r\n Please refer to the manual.\n");
    }

    cDEBUG("\n FLASH_Test_Case1 End!\n");
}


/*******************************************************************************
 * @brief      FLASH_Test_Case2
 *              CFlash ChipErase DwProgram WordRead Demo (except Shadow/Test).
 *              1. Must be unlocked first.
 *              2. CFlash cannot erase/programming CFlash, 
 *                 Functions needs to run in RAM.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case2(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t startAddr = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    CFlash_UnlockBlocksInit();
    /* Flash Select Block Cancel */
    CFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case2 Start!\n");

    /* 1.Increasing Programming Test
     * ********************************/
    /* Erase */
#ifndef CONFIG_FLASH
    retStatus = CFlash_ChipErase();
    startAddr = CFLASH_SECTOR0_START;
#else
    retStatus = CFlash_BlockErase((CFLASH_LMS_LSL4|CFLASH_LMS_LSL5), CFLASH_LMS_M0_1, CFLASH_HBS_NULL);
    startAddr = CFLASH_SECTOR4_START;
#endif
    if (retStatus != 0U)
    {
        cDEBUG("\n CFlash_ChipErase fail 1: 0x%x!\n", retStatus);
        Bug();
    }
    /* Read checks erased data */
    for(i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += 4U)
    {
        if (CFlash_WordRead(i) != 0xFFFFFFFFU)
        {
            cDEBUG("\n Erase data fail 1: 0x%x!\n", i);
            Bug();
        }
    }
    /* Program */
    for(i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += 8U)
    {
        retStatus = CFlash_DwProgram(i, i + 4U, i);
        if (retStatus != 0U)
        {
            cDEBUG("\n CFlash_DwProgram fail 1: 0x%x!\n", retStatus);
            Bug();
        }
    }
    /* Read check the programmed data */
    for(i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += 4U)
    {
        if (CFlash_WordRead(i) != i)
        {
            cDEBUG("\n Program data fail 1: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case2 End!\n");
}

/*******************************************************************************
 * @brief      FLASH_Test_Case3
 *              CFlash BlockErase Program ByteRead Demo (except Shadow/Test).
 *              1. Must be unlocked first.
 *              2. CFlash cannot erase/programming CFlash, 
 *                 Functions needs to run in RAM.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case3(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t addr = 0U;
    uint32_t size = 0U;
    uint32_t tmpSize = 2048U; /* 512*4 = 2048 Byte */
    uint32_t tmpBuf[512] = {0U};
    uint32_t startIndex = 0U;

    for (i = 0U; i < 512U; i++)
    {
        tmpBuf[i] = 0x55555555U;
    }

    /* Flash must be unlocked before it can be erased and programmed */
    CFlash_UnlockBlocksInit();
    /* Flash Select Block Cancel */
    CFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case3 Start!\n");

    /* 2.Fixed Value Programming Test
     * ********************************/
#ifndef CONFIG_FLASH
    startIndex = 0U;
#else
    startIndex = 4U;
#endif
    /* CFlash Low Address Space Test ( 6 Low Address Blocks) */
    for (i = startIndex; i < 6U; i++)
    {
        retStatus = CFlash_GetLowSectorAddrSize(CFlash_LSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = CFlash_BlockErase(CFlash_LSL_All[i], CFLASH_LMS_NULL, CFLASH_HBS_NULL);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_BlockErase fail LSL: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
            /* Program */
            for (j = 0U; j < size; j += tmpSize)
            {
                retStatus = CFlash_Program((addr + j), tmpSize, tmpBuf);
                if (retStatus != 0U)
                {
                    cDEBUG("\n CFlash_Program fail: 0x%x!\n", retStatus);
                    Bug();
                }
            }
            /* Read and Check Programmed data */
            for (j = 0U; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0x55U)
                {
                    cDEBUG("\n Program CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
        }
        else
        {
            cDEBUG("\n Get CFlash LSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    /* CFlash Mid Address Space Test ( 2 Mid Address Blocks) */
    for (i = 0U; i < 2U; i++)
    {
        retStatus = CFlash_GetMidSectorAddrSize(CFlash_MSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = CFlash_BlockErase(CFLASH_LMS_NULL, CFlash_MSL_All[i], CFLASH_HBS_NULL);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_BlockErase fail MSL: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0U; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
            /* Program */
            for (j = 0U; j < size; j += tmpSize)
            {
                retStatus = CFlash_Program((addr + j), tmpSize, tmpBuf);
                if (retStatus != 0U)
                {
                    cDEBUG("\n CFlash_Program fail: 0x%x!\n", retStatus);
                    Bug();
                }
            }
            /* Read and Check Programmed data */
            for (j = 0U; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0x55U)
                {
                    cDEBUG("\n Program CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
        }
        else
        {
            cDEBUG("\n Get CFlash MSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case3 End!\n");
}

/*******************************************************************************
 * @brief      FLASH_Test_Case4
 *              CFlash PageErase DwProgram WordRead Demo (except Shadow/Test).
 *              1. Must be unlocked first.
 *              2. CFlash cannot erase/programming CFlash, 
 *                 Functions needs to run in RAM.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case4(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t startAddr = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    CFlash_UnlockBlocksInit();
    /* Flash Select Block Cancel */
    CFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case4 Start!\n");

    /* 3.Decrement programming tests
     * ********************************/
    /* Erase */
#ifndef CONFIG_FLASH
    startAddr = CFLASH_SECTOR0_START;
#else
    startAddr = CFLASH_SECTOR4_START;
#endif
    for (i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += PAGE_SIZE)
    {
        retStatus = CFlash_PageErase(i);
        if (retStatus != 0U)
        {
            cDEBUG("\n Erase data fail 4: 0x%x!\n", i);
            Bug();
        }
    }

    /* Read checks erased data */
    for (i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += WORD_SIZE)
    {
        if (CFlash_WordRead(i) != 0xFFFFFFFFU)
        {
            cDEBUG("\n Erase data fail 4: 0x%x!\n", i);
            Bug();
        }
    }
    /* Program */
    i = (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE - DWORD_SIZE);
    for (j = startAddr; j < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); j += DWORD_SIZE)
    {
        retStatus = CFlash_DwProgram(j + WORD_SIZE, j, i);
        if (retStatus != 0U)
        {
            cDEBUG("\n CFlash_DwProgram fail 4: 0x%x!\n", retStatus);
            Bug();
        }
        if (i >= DWORD_SIZE)
        {
            i -= DWORD_SIZE;
        }
    }
    j = 0U;
    /* Read check the programmed data */
    for (i = startAddr; i < (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE); i += WORD_SIZE)
    {
        if (CFlash_WordRead(i) != (CFLASH_SECTOR7_START + CFLASH_SECTOR7_SIZE - WORD_SIZE - j))
        {
            cDEBUG("\n Program data fail 4: 0x%x!\n", i);
            Bug();
        }
        j += WORD_SIZE;
    }

    cDEBUG("\n FLASH_Test_Case4 End!\n");
}


/*******************************************************************************
 * @brief      FLASH_Test_Case6
 *             DFlash ChipErase DwProgram WordRead Demo (except Test).
 *             Must be unlocked first.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case6(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    DFlash_UnlockBlocksInit();
    DFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case6 Start!\n");

    /* 1.Increasing programming tests
     * ********************************/
    /* Erase */
    retStatus = DFlash_ChipErase();
    if (retStatus != 0U)
    {
        cDEBUG("\n DFlash_ChipErase fail 1: 0x%x!\n", retStatus);
        Bug();
    }
    /* Read checks erased data */
    for (i = DFLASH_SECTOR0_START; i < (DFLASH_SECTOR3_START + DFLASH_SECTOR3_SIZE); i += 4U)
    {
        if (DFlash_WordRead(i) != 0xFFFFFFFFU)
        {
            cDEBUG("\n DFlash Erase data fail 1: 0x%x!\n", i);
            Bug();
        }
    }
    /* Program */
    for (i = DFLASH_SECTOR0_START; i < (DFLASH_SECTOR3_START + DFLASH_SECTOR3_SIZE); i += 8U)
    {
        retStatus = DFlash_DwProgram(i, i + 4U, i);
        if (retStatus != 0U)
        {
            cDEBUG("\n DFlash_DwProgram fail 1: 0x%x!\n", retStatus);
            Bug();
        }
    }
    /* Read check the programmed data */
    for (i = DFLASH_SECTOR0_START; i < (DFLASH_SECTOR3_START + DFLASH_SECTOR3_SIZE); i += 4U)
    {
        if (DFlash_WordRead(i) != i)
        {
            cDEBUG("\n DFlash Program data fail 1: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case6 End!\n");
}

/*******************************************************************************
 * @brief      FLASH_Test_Case7
 *             DFlash BlockErase Program ByteRead Demo (except Test).
 *             Must be unlocked first.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case7(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t addr = 0U;
    uint32_t size = 0U;
    uint32_t tmpSize = 2048U; /* 512*4 = 2048 Byte */
    uint32_t tmpBuf[512] = {0U};

    for (i = 0U; i < 512U; i++)
    {
        tmpBuf[i] = 0xAAAAAAAAU;
    }

    /* Flash must be unlocked before it can be erased and programmed */
    DFlash_UnlockBlocksInit();
    DFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case7 Start!\n");

    /* 2.Fixed value 1 programming tests
     * ********************************/

    /* DFlash Low Address Space Test ( 4 Low Address Blocks) */
    for (i = 0U; i < 4U; i++)
    {
        retStatus = DFlash_GetLowSectorAddrSize(DFlash_LSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = DFlash_BlockErase(DFlash_LSL_All[i]);
            if (retStatus != 0U)
            {
                cDEBUG("\n DFlash_BlockErase fail LSL: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0U; j < size; j += 1U)
            {
                if (DFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase DFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
            /* Program */
            for (j = 0U; j < size; j += tmpSize)
            {
                retStatus = DFlash_Program((addr + j), tmpSize, tmpBuf);
                if (retStatus != 0U)
                {
                    cDEBUG("\n DFlash_Program fail: 0x%x!\n", retStatus);
                    Bug();
                }
            }
            /* Read and Check Programmed data */
            for (j = 0U; j < size; j += 1U)
            {
                if (DFlash_ByteRead(addr + j) != 0xAAU)
                {
                    cDEBUG("\n Program DFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }
        }
        else
        {
            cDEBUG("\n Get DFlash LSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case7 End!\n");
}

/*******************************************************************************
 * @brief      FLASH_Test_Case8
 *             DFlash PageErase DwProgram WordRead Demo (except Test).
 *             Must be unlocked first.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case8(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    DFlash_UnlockBlocksInit();
    DFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case8 Start!\n");

    /* 3.Decrement programming tests
     * ********************************/
    /* Erase */
    for (i = DFLASH_SECTOR0_START; i < (DFLASH_SECTOR3_START + DFLASH_SECTOR3_SIZE); i += PAGE_SIZE)
    {
        retStatus = DFlash_PageErase(i);
        if (retStatus != 0U)
        {
            cDEBUG("\n DFlash_PageErase fail 4: 0x%x!\n", retStatus);
            Bug();
        }
    }
    /* Read checks erased data */
    for (i = DFLASH_SECTOR0_START; i < (DFLASH_SECTOR3_START + DFLASH_SECTOR3_SIZE); i += WORD_SIZE)
    {
        if (DFlash_WordRead(i) != 0xFFFFFFFFU)
        {
            cDEBUG("\n DFlash Erase data fail 4: 0x%x!\n", i);
            Bug();
        }
    }
    /* Program */
    i = (DFLASH_LOW0_3_SIZE - DWORD_SIZE);
    for (j = 0U; j < DFLASH_LOW0_3_SIZE; j += DWORD_SIZE)
    {
        retStatus = DFlash_DwProgram(j + WORD_SIZE, j, DFLASH_SECTOR0_START + i);
        if (retStatus != 0U)
        {
            cDEBUG("\n DFlash_DwProgram fail 4: 0x%x!\n", retStatus);
            Bug();
        }
        if (i >= DWORD_SIZE)
        {
            i -= DWORD_SIZE;
        }
    }
    /* Read check the programmed data */
    for (i = 0U; i < (DFLASH_LOW0_3_SIZE); i += WORD_SIZE)
    {
        if (DFlash_WordRead(DFLASH_SECTOR0_START + i) != (DFLASH_LOW0_3_SIZE - WORD_SIZE - i))
        {
            cDEBUG("\n DFlash Program data fail 4: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case8 End!\n");
}

/*******************************************************************************
 * @brief      Flash_UnAlign_Read_And_Compare
 * @param[in]  uint32_t addr
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Flash_UnAlign_Read_And_Compare(uint32_t addr)
{
    uint32_t i = 0U;
    uint32_t ramBuf[2] = {0U};
    uint8_t sRamVal = 0U;
    uint8_t dFlashVal = 0U;

    /* Step 1: Clear Ram Buffer */
    cc_memset((uint8_t *)ramBuf, 0x00U, 8U);

    /* Step 2: Copy DFlash Data To Ram (DFlash address is not word align) */
    cc_memcpy((uint8_t *)(ramBuf), (uint8_t *)(addr + 1U), 3U);

    /* Step 3: Copy DFlash Data To Ram (Ram address is not word align) */
    cc_memcpy((uint8_t *)(ramBuf) + 3U, (uint8_t *)(addr + 4U), 4U);

    /* Step 4: Compare Data in DFlash and Ram */
    for (i = 0x0U; i < 0x07U; i++)
    {
        dFlashVal = DFlash_ByteRead(addr + 1U + i);
        sRamVal = *((uint8_t *)ramBuf + i);
        if (dFlashVal != sRamVal)
        {
            cDEBUG("\n Flash_UnAlign_Read_And_Compare fail !\n");
            Bug();
        }
    }
}

/*******************************************************************************
 * @brief      FLASH_Test_Case9
 *             DFlash UnAligned Read Demo (except Test).
 *             Must be unlocked first.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case9(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t addr = 0U;
    uint32_t size = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    DFlash_UnlockBlocksInit();
    DFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case9 Start!\n");

    /* DFlash Low Address Space Test ( 4 Low Address Blocks) */
    for (i = 0U; i < 4U; i++)
    {
        retStatus = DFlash_GetLowSectorAddrSize(DFlash_LSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = DFlash_BlockErase(DFlash_LSL_All[i]);
            if (retStatus != 0U)
            {
                cDEBUG("\n DFlash_BlockErase fail: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0U; j < size; j += 1U)
            {
                if (DFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase DFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }

            /* UnAligned Read at the Begin of Block */

            retStatus = DFlash_DwProgram(0x11223344U, 0x55667788U, addr);
            if (retStatus != 0U)
            {
                cDEBUG("\n DFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr);

            /* UnAligned Read at the End of Block */

            retStatus = DFlash_DwProgram(0x12345678U, 0xAABBCCDDU, addr+size-8U);
            if (retStatus != 0U)
            {
                cDEBUG("\n DFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr+size-8U);
        }
        else
        {
            cDEBUG("\n Get DFlash LSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case9 End!\n");
}

/*******************************************************************************
 * @brief      FLASH_Test_Case5
 *             CFlash UnAligned Read Demo (except Shadow/Test).
 *             1. Must be unlocked first.
 *             2. CFlash cannot erase/programming CFlash, 
 *                 Functions needs to run in RAM.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void FLASH_Test_Case5(void) /* PRQA S 3219 */
{
    uint32_t retStatus = 0U;
    uint32_t i = 0U;
    uint32_t j = 0U;
    uint32_t addr = 0U;
    uint32_t size = 0U;
    uint32_t startIndex = 0U;

    /* Flash must be unlocked before it can be erased and programmed */
    CFlash_UnlockBlocksInit();
    /* Flash Select Block Cancel */
    CFlash_BlockSelect_Cancel();

    cDEBUG("\n FLASH_Test_Case5 Start!\n");
#ifndef CONFIG_FLASH
    startIndex = 0U;
#else
    startIndex = 4U;
#endif
    /* CFlash Low Address Space Test ( 6 Low Address Blocks) */
    for (i = startIndex; i < 6U; i++)
    {
        retStatus = CFlash_GetLowSectorAddrSize(CFlash_LSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = CFlash_BlockErase(CFlash_LSL_All[i], CFLASH_LMS_NULL, CFLASH_HBS_NULL);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_BlockErase fail LSL: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0U; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }

            /* UnAligned Read at the Begin of Block */

            retStatus = CFlash_DwProgram(0x11223344U, 0x55667788U, addr);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr);

            /* UnAligned Read at the End of Block */

            retStatus = CFlash_DwProgram(0x12345678U, 0xAABBCCDDU, addr+size-8U);
            if (retStatus !=0U)
            {
                cDEBUG("\n CFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr+size-8U);
        }
        else
        {
            cDEBUG("\n Get CFlash LSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    /* CFlash Mid Address Space Test ( 2 Mid Address Blocks) */
    for (i = 0U; i < 2U; i++)
    {
        retStatus = CFlash_GetMidSectorAddrSize(CFlash_MSL_All[i], &addr, &size);
        if (retStatus == 0x00000000U)
        {
            /* Block Erase */
            retStatus = CFlash_BlockErase(CFLASH_LMS_NULL, CFlash_MSL_All[i], CFLASH_HBS_NULL);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_BlockErase fail MSL: 0x%x!\n", retStatus);
                Bug();
            }
            /* Read and Check Erased Data */
            for (j = 0U; j < size; j += 1U)
            {
                if (CFlash_ByteRead(addr + j) != 0xFFU)
                {
                    cDEBUG("\n Erase CFlash_ByteRead Check fail: 0x%x!\n", j);
                    Bug();
                }
            }

            /* UnAligned Read at the Begin of Block */

            retStatus = CFlash_DwProgram(0x11223344U, 0x55667788U, addr);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr);

            /* UnAligned Read at the End of Block */

            retStatus = CFlash_DwProgram(0x12345678U, 0xAABBCCDDU, addr+size-8U);
            if (retStatus != 0U)
            {
                cDEBUG("\n CFlash_DwProgram fail: 0x%x!\n", retStatus);
                Bug();
            }

            Flash_UnAlign_Read_And_Compare(addr+size-8U);
        }
        else
        {
            cDEBUG("\n Get CFlash MSL addr and size fail: 0x%x!\n", i);
            Bug();
        }
    }

    cDEBUG("\n FLASH_Test_Case5 End!\n");
}

/*******************************************************************************
 * @brief      FLASH Test Demo.
 *             Erase: unlock + select.
 *             Program: unlock.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void FLASH_Test_Demo(void)
{
    /* Function: Init Access Code.*/
    CFlash_AC_Init();

	/* Function: Read Flash register(after reset) and comparison.*/
#if FLASH_CASE1
    FLASH_Test_Case1();
#endif

    /* Function: CFlash ChipErase DwProgram WordRead Demo . */
#if FLASH_CASE2
    FLASH_Test_Case2();
#endif

    /* Function: CFlash BlockErase Program ByteRead Demo . */
#if FLASH_CASE3
    FLASH_Test_Case3();
#endif

    /* Function: CFlash PageErase DwProgram WordRead Demo . */
#if FLASH_CASE4
    FLASH_Test_Case4();
#endif

    /* Function: CFlash UnAligned Read Demo . */
#if FLASH_CASE5
    FLASH_Test_Case5();
#endif

    /* Function: DFlash ChipErase DwProgram WordRead Demo .*/
#if FLASH_CASE6
    FLASH_Test_Case6();
#endif

    /* Function: DFlash BlockErase Program ByteRead Demo . */
#if FLASH_CASE7
    FLASH_Test_Case7();
#endif

    /* Function: DFlash PageErase DwProgram WordRead Demo . */
#if FLASH_CASE8
    FLASH_Test_Case8();
#endif

    /* Function: DFlash UnAligned Read Demo . */
#if FLASH_CASE9
    FLASH_Test_Case9();
#endif
}
